package nbcp.myoql.db.sql.event;

import nbcp.base.extend.*
import nbcp.base.utils.CodeUtil
import nbcp.base.utils.ReflectUtil
import nbcp.myoql.db.comm.EventResult
import nbcp.myoql.db.db
import nbcp.myoql.db.mongo.MongoEntityCollector
import nbcp.myoql.db.sql.annotation.AutoIdColumn
import nbcp.myoql.db.sql.annotation.AutoNumberColumn
import nbcp.myoql.db.sql.annotation.ConverterValueToDb
import nbcp.myoql.db.sql.base.IFieldValueConverter
import nbcp.myoql.db.sql.component.SqlInsertClip
import nbcp.myoql.db.sql.extend.proc_value
import org.springframework.stereotype.Component
import java.lang.reflect.Field

/**
 * 处理删除数据后转移到垃圾箱功能
 */
@Component
class SqlDefaultInsertEvent : ISqlEntityInsert {

    private class AutoIdConverter : IFieldValueConverter {
        override fun convert(field: Field, value: Any?): Any? {
            if (field.type == Long::class.java) {
                if (value == null || value.AsLong(0) == 0L) {
                    return CodeUtil.getNumberValue();
                }
            } else if (field.type.IsStringType) {
                if (value.AsString().isNullOrEmpty()) {
                    return CodeUtil.getCode();
                }
            } else {
                throw RuntimeException("AutoId必须是字符串或长整型")
            }

            return value;
        }
    }

    override fun beforeInsert(insert: SqlInsertClip<*, *>): EventResult {
        //先处理 SqlAutoIncrementKey
        insert.mainEntity.getAutoIncrementKey()
            .apply {
                if (this.HasValue) {
                    insert.entities
                        .forEach { ent ->
                            ent.remove(this);
                        }
                }
            }

        var insertEntityType = insert.mainEntity::class.java;
        var autoId = insertEntityType.getAnnotation(AutoIdColumn::class.java) as AutoIdColumn?
        if (autoId != null) {
            var converterClass = ConverterValueToDb(autoId.value, AutoIdConverter::class);
            convertValueProc(converterClass, insert)
        }

        var autoNumber = insertEntityType.getAnnotation(AutoNumberColumn::class.java) as AutoNumberColumn?
        if (autoNumber != null) {
            var converterClass = ConverterValueToDb(autoNumber.value, AutoIdConverter::class);
            convertValueProc(converterClass, insert)
        }

        //再处理 AutoId
        insertEntityType.getAnnotationsByType(ConverterValueToDb::class.java)
            .forEach { converterClass ->
                convertValueProc(converterClass, insert)
            }


        //处理 Json 类型的数据
        insert.mainEntity.getJsonColumns()
            .forEach { column ->
                insert.entities.forEach { ent ->
                    val v = ent.get(column.name)
                    if (v != null) {
                        var v_type = v::class.java
                        if (v_type.IsStringType == false) {
                            ent.put(column.name, v.ToJson())
                        }
                    }
                }
            }


        //把 布尔值 改为 1,0
        insert.mainEntity.systemDefineEntityType.AllFields
            .forEach { field ->
                insert.entities.forEach { ent ->
                    var key = field.name;
                    var value = ent.get(key);
                    if (value == null) {
                        ent.remove(key);
                        return@forEach
                    }

                    ent.set(key, proc_value(value));
                }
            }


        // 处理 SpreadColumn
        insert.mainEntity.getSpreadColumns()
            .forEach { spread ->
                insert.entities.forEach { entity ->
                    val value = entity.get(spread.column)?.ConvertType(Map::class.java) as Map<String, Any?>?;
                    if (value == null) {
                        return@forEach
                    }

                    value.keys.forEach { key ->
                        entity.set(spread.getPrefixName() + key, value.get(key))
                    }

                    entity.remove(spread.column)
                }
            }

        return EventResult(true)
    }

    private fun convertValueProc(
        converterClass: ConverterValueToDb,
        insert: SqlInsertClip<*, *>
    ) {
        var converter = converterClass.value.java.getConstructor().newInstance()
        var field = insert.mainEntity.systemDefineEntityType.FindField(converterClass.field);
        if (field == null) {
            throw RuntimeException("实体:${insert.mainEntity.systemDefineEntityType.simpleName} 定义的 ConverterValueToDb 找不到字段: ${converterClass.field} !")
        }
        field.isAccessible = true;

        insert.entities.forEach { ent ->
            val v = ent.get(converterClass.field)
            ent.put(converterClass.field, converter.convert(field, v))
        }
    }

    override fun insert(insert: SqlInsertClip<*, *>, eventData: EventResult) {
        brokeCache(insert)
    }

    private fun brokeCache(insert: SqlInsertClip<*, *>) {
        val cacheGroups = MongoEntityCollector.sysRedisCacheDefines.get(insert.tableName)
        if (cacheGroups == null) {
            return;
        }

        cacheGroups.forEach { groupKeys ->
            insert.entities.forEach { ent ->
                val groupValue = groupKeys.map {
                    return@map it to ReflectUtil.getValueByWbsPath(ent, it).AsString()
                }.filter { it.second.HasValue }
                    .toMap();

                if (groupValue.keys.size != groupKeys.size) {
                    clearAllCache(insert.tableName);
                    return;
                }


                db.brokeRedisCache(
                    table = insert.tableName,
                    groupKey = groupValue.keys.joinToString(","),
                    groupValue = groupValue.values.joinToString(",")
                )
            }
        }
    }

    private fun clearAllCache(tableName: String) {
        db.brokeRedisCache(
            table = tableName,
            groupKey = "",
            groupValue = ""
        )
    }
}